/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gw.reportbuilder;

import gw.reportbuilder.column.Column;
import gw.reportbuilder.filter.Filter;
import gw.reportbuilder.filter.Operator;
import gw.reportbuilder.table.Table;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author Sostenes
 */
public class ReportBuilderController extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String acao = request.getParameter("acao");
        RequestDispatcher dispatcher;
        String url;

        try {

            if ("getViews".equals(acao)) {

                listViews(request, response);
                url = "/reportBuilder/report_builder.jsp";
                dispatcher = request.getRequestDispatcher(url);
                dispatcher.forward(request, response);

            } else if ("getColumns".equals(acao)) {

                getColumns(request, response);
                url = "/reportBuilder/ajax/column_list.jsp";
                dispatcher = request.getRequestDispatcher(url);
                dispatcher.forward(request, response);

            } else if ("doReport".equals(acao)) {

                doReport(request, response);
                url = "/reportBuilder/report_result.jsp";
                dispatcher = request.getRequestDispatcher(url);
                dispatcher.forward(request, response);

            } else if ("getFilterValues".equals(acao)) {

                getFilterValues(request, response);
                url = "/reportBuilder/ajax/filter_value.jsp";
                dispatcher = request.getRequestDispatcher(url);
                dispatcher.forward(request, response);

            } else if ("saveReport".equals(acao)) {

                saveReport(request, response);
                url = "/ReportBuilderController?acao=listReports";
                dispatcher = request.getRequestDispatcher(url);
                dispatcher.forward(request, response);

            } else if ("openReport".equals(acao)) {

                openReport(request, response);
                url = "/reportBuilder/report.jsp";
                dispatcher = request.getRequestDispatcher(url);
                dispatcher.forward(request, response);

            } else if ("listReports".equals(acao)) {

                listReports(request, response);
                url = "/reportBuilder/list.jsp";
                dispatcher = request.getRequestDispatcher(url);
                dispatcher.forward(request, response);

            } else if ("deleteReport".equals(acao)) {

                deleteReport(request, response);
                url = "/ReportBuilderController?acao=listReports";
                dispatcher = request.getRequestDispatcher(url);
                dispatcher.forward(request, response);

            } else if ("checkReportExists".equals(acao)) {

                checkReportExists(request, response);

            } else {

                url = "/ReportBuilderController?acao=listReports";
                dispatcher = request.getRequestDispatcher(url);
                dispatcher.forward(request, response);
            }

        } catch (Exception ex) {

            throw new ServletException(ex);
        }
    }
    
    private void checkReportExists(HttpServletRequest request, HttpServletResponse response) throws Exception {
        
        ReportBO bo = new ReportBO();
        
        String reportTitle = request.getParameter("reportTitle");
        boolean exists = bo.checkReportExists(reportTitle);
        
        PrintWriter writer = response.getWriter();
        
        writer.printf("{\"exists\": %b}", exists);
    }

    private void deleteReport(HttpServletRequest request, HttpServletResponse response) throws Exception {

        ReportBO bo = new ReportBO();

        String reportId = request.getParameter("reportId");

        int id = Integer.parseInt(reportId);
        bo.deleteReport(id);
    }

    private void listReports(HttpServletRequest request, HttpServletResponse response) throws Exception {

        ReportBO bo = new ReportBO();
        Map<Integer, String> reportMap = bo.listReports();

        request.setAttribute("reportMap", reportMap);

    }

    private void listViews(HttpServletRequest request, HttpServletResponse response) throws Exception {

        ReportBO bo = new ReportBO();

        List<Table> viewList = bo.getViewList();

        request.setAttribute("viewList", viewList);
    }

    private void getColumns(HttpServletRequest request, HttpServletResponse response) throws Exception {

        ReportBO bo = new ReportBO();
        String viewName = request.getParameter("viewName");
        String viewLabel = request.getParameter("viewLabel");
        List<Column> columns = bo.getColumns(viewName);

        request.setAttribute("viewName", viewName);
        request.setAttribute("viewLabel", viewLabel);
        request.setAttribute("columnList", columns);
    }

    private void getFilterValues(HttpServletRequest request, HttpServletResponse response) throws Exception {

        ReportBO bo = new ReportBO();
        String viewName = request.getParameter("viewName");
        String columnName = request.getParameter("columnName");
        String columnType = request.getParameter("columnType");
        String operator = request.getParameter("operator");

        List<String> columnValues = bo.getColumnValues(viewName, columnName);

        request.setAttribute("columnName", columnName);
        request.setAttribute("columnValues", columnValues);
        request.setAttribute("operator", operator);
        request.setAttribute("columnType", columnType);
    }

    private void openReport(HttpServletRequest request, HttpServletResponse response) throws Exception {

        ReportBO bo = new ReportBO();
        String reportId = request.getParameter("reportId");
        Map<Filter, List<Operator>> operatorsMap = new LinkedHashMap<Filter, List<Operator>>();

        int id = Integer.parseInt(reportId);
        Report report = bo.getReport(id);

        List<Filter> filters = report.getFilters();

        for (Filter filter : filters) {

            List<Operator> operators = bo.getOperators(report.getTable().getName(), filter.getColumn().getName(), filter.getColumn().getType());

            operatorsMap.put(filter, operators);
        }

        request.setAttribute("operators", operatorsMap);
        request.setAttribute("report", report);
    }

    private void doReport(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String export = request.getParameter("export");

        Report report = getReport(request, response);

        ReportBO bo = new ReportBO();
        Collection<Object[]> reportResult = bo.getReportResult(report);

        request.setAttribute("report", report);
        request.setAttribute("result", reportResult);
        request.setAttribute("export", export);
    }

    private void saveReport(HttpServletRequest request, HttpServletResponse response) throws Exception {

        Report report = getReport(request, response);

        ReportBO bo = new ReportBO();

        bo.saveReport(report);

        request.setAttribute("report", report);
    }

    private Report getReport(HttpServletRequest request, HttpServletResponse response) {

        Map<String, String[]> columnMap = getAssocParamMap("column", request);
        Map<String, String[]> labelMap = getAssocParamMap("label", request);
        Map<String, String[]> typeMap = getAssocParamMap("type", request);
        Map<String, String[]> filterMap = getAssocParamMap("filter", request);
        Map<String, String[]> operatorMap = getAssocParamMap("op", request);
        String viewName = request.getParameter("viewName");
        String viewLabel = request.getParameter("viewLabel");
        String reportTitle = request.getParameter("reportTitle");


        Table table = new Table(viewName, viewLabel);

        ArrayList<Column> columns = getColumns(columnMap, labelMap, typeMap);

        ArrayList<Filter> filters = getFilters(filterMap, labelMap, typeMap, operatorMap);

        ReportBO bo = new ReportBO();

        return bo.getReport(reportTitle, table, columns, filters);
    }

    private ArrayList<Column> getColumns(Map<String, String[]> columnMap, Map<String, String[]> labelMap,
            Map<String, String[]> typeMap) {

        ArrayList<Column> columns = new ArrayList<Column>();

        for (String key : columnMap.keySet()) {

            Column column = new Column(key, labelMap.get(key)[0], typeMap.get(key)[0]);
            columns.add(column);
        }
        return columns;
    }

    private ArrayList<Filter> getFilters(Map<String, String[]> filterMap, Map<String, String[]> labelMap,
            Map<String, String[]> typeMap, Map<String, String[]> operatorMap) {

        ArrayList<Filter> filters = new ArrayList<Filter>();

        for (String key : filterMap.keySet()) {

            Column column = new Column(key, labelMap.get(key)[0], typeMap.get(key)[0]);

            Filter filter = new Filter(column);

            if (!operatorMap.isEmpty()) {

                String op = operatorMap.get(key)[0];

                if (op != null && !op.isEmpty()) {

                    Operator operator = Operator.valueOf(op);
                    filter.setOperator(operator);
                    filter.setArguments(filterMap.get(key));
                }

            }

            filters.add(filter);
        }

        return filters;
    }

    private Map<String, String[]> getAssocParamMap(String parameter, HttpServletRequest request) {

        Map<String, String[]> parameterMap = request.getParameterMap();

        Map<String, String[]> assocMap = new LinkedHashMap<String, String[]>();

        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {

            String name = entry.getKey();

            if (name.startsWith(parameter + "[")) {

                String key = name.substring(name.indexOf('[') + 1, name.indexOf(']'));
                assocMap.put(key, entry.getValue());
            }
        }

        return assocMap;
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
